package service

import (
	"context"
	"errors"
	"gitee.com/Frank098/devops-app-mgt/cache"
	"gitee.com/Frank098/devops-app-mgt/model"
	"gitee.com/Frank098/devops-app-mgt/utils"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
	"time"
)

var Svc svc

type svc struct{}

func (s *svc) GetServiceInfo(serviceName, namespace string) (service *corev1.Service, err error) {
	service, err = cache.ServiceCache.GetServiceRedisCache("service" + "_" + serviceName + "_" + namespace)
	if err != nil {
		service, err = K8s.ClientSet.CoreV1().Services(namespace).Get(context.TODO(), serviceName, metav1.GetOptions{})
		if err != nil {
			return nil, errors.New("获取Service详情失败, " + err.Error())
		}
		if err = cache.ServiceCache.SetServiceRedisCache("service"+"_"+serviceName+"_"+namespace, service); err != nil {
			return nil, errors.New("写入缓存数据失败," + err.Error())
		}
		return service, nil
	}
	return service, nil
}

func (s *svc) CreateService(data *model.ServiceCreate) (err error) {
	//将data中的数据组装成corev1.Service对象
	service := &corev1.Service{
		//ObjectMeta中定义资源名、命名空间以及标签
		ObjectMeta: metav1.ObjectMeta{
			Name:      data.Name,
			Namespace: data.Namespace,
		},
		//Spec中定义类型，端口，选择器
		Spec: corev1.ServiceSpec{
			Type: corev1.ServiceType(data.Type),
		},
	}
	//组装ports
	var servicePort []corev1.ServicePort
	if data.Type == "NodePort" {
		for _, value := range data.ServicePortList {
			for _, valueList := range value {
				sp := corev1.ServicePort{
					Name:     valueList.PortName,
					Port:     valueList.Port,
					Protocol: "TCP",
					TargetPort: intstr.IntOrString{
						Type:   0,
						IntVal: valueList.ContainerPort,
					},
					NodePort: valueList.NodePort,
				}
				servicePort = append(servicePort, sp)
			}
			service.Spec.Ports = servicePort
		}
	} else if data.Type == "ClusterIP" {
		for _, value := range data.ServicePortList {
			for _, valueList := range value {
				sp := corev1.ServicePort{
					Name:     valueList.PortName,
					Port:     valueList.Port,
					Protocol: "TCP",
					TargetPort: intstr.IntOrString{
						Type:   0,
						IntVal: valueList.ContainerPort,
					},
				}
				servicePort = append(servicePort, sp)
			}
			service.Spec.Ports = servicePort
		}
	}
	//组装标签与选择器
	var label = make(map[string]string)
	for key, value := range data.Label {
		label[key] = value
	}
	service.ObjectMeta.Labels = label
	service.Spec.Selector = label
	//创建Service
	_, err = K8s.ClientSet.CoreV1().Services(data.Namespace).Create(context.TODO(), service, metav1.CreateOptions{})
	if err != nil {
		return errors.New("创建Service失败, " + err.Error())
	}

	return nil
}

func (s *svc) DeleteService(serviceName, namespace string) (err error) {
	err = K8s.ClientSet.CoreV1().Services(namespace).Delete(context.TODO(), serviceName, metav1.DeleteOptions{})
	if err != nil {
		return errors.New("删除Service失败, " + err.Error())
	}

	return nil
}

func (s *svc) GetSvcAllPerNp() (svcNps []*model.GetSvcList, err error) {
	svcNps, err = cache.ServiceCache.GetServiceNpRedisCache("svcNps")
	if err != nil {
		namespaceList, err := K8s.ClientSet.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})
		if err != nil {
			return nil, errors.New("获取命名空间列表失败," + err.Error())
		}
		for _, namespace := range namespaceList.Items {
			svcNp, err := s.GetSvcSingleNp(namespace.Name)
			if err != nil {
				return nil, errors.New("获取pod列表失败," + err.Error())
			}

			svcNps = append(svcNps, svcNp...)
		}
		if err = cache.ServiceCache.SetServiceNpRedisCache("svcNps", svcNps); err != nil {
			return nil, errors.New("写入缓存数据失败," + err.Error())
		}
		return svcNps, nil
	}

	return svcNps, nil
}

func (s *svc) GetSvcSingleNp(namespace string) (svcNps []*model.GetSvcList, err error) {
	svcNps, err = cache.ServiceCache.GetServiceNpRedisCache("svcNps_" + namespace)
	if err != nil {
		svcList, err := K8s.ClientSet.CoreV1().Services(namespace).List(context.TODO(), metav1.ListOptions{})
		if err != nil {
			return nil, errors.New("获取svc列表失败," + err.Error())
		}
		for _, svcListInfo := range svcList.Items {
			//组装数据
			currentContainerTime := svcListInfo.CreationTimestamp
			dateOfDifference := utils.SubDays(time.Now(), currentContainerTime.Time)
			if string(svcListInfo.Spec.Type) == "ClusterIP" {
				//组装数据
				svcNp := &model.GetSvcList{
					Name:      svcListInfo.Name,
					Namespace: svcListInfo.Namespace,
					Target:    svcListInfo.Spec.Ports[0].Name + ":" + svcListInfo.Spec.Ports[0].TargetPort.String() + "/" + string(svcListInfo.Spec.Ports[0].Protocol),
					Selector:  svcListInfo.Spec.Selector,
					Type:      string(svcListInfo.Spec.Type),
					Age:       dateOfDifference,
				}
				svcNps = append(svcNps, svcNp)
			} else if string(svcListInfo.Spec.Type) == "NodePort" {
				nodePort := s.Int32TypeConversion(svcListInfo.Spec.Ports[0].NodePort)
				svcNp := &model.GetSvcList{
					Name:      svcListInfo.Name,
					Namespace: svcListInfo.Namespace,
					Target:    "[Any Node]:" + nodePort + "/" + string(svcListInfo.Spec.Ports[0].Protocol),
					Selector:  svcListInfo.Spec.Selector,
					Type:      string(svcListInfo.Spec.Type),
					Age:       dateOfDifference,
				}
				svcNps = append(svcNps, svcNp)
			}
		}
		if err = cache.ServiceCache.SetServiceNpRedisCache("svcNps_"+namespace, svcNps); err != nil {
			return nil, errors.New("写入缓存数据失败," + err.Error())
		}
		return svcNps, nil
	}
	return svcNps, nil
}

func (s *svc) Int32TypeConversion(n int32) string {
	buf := [11]byte{}
	pos := len(buf)
	i := int64(n)
	signed := i < 0
	if signed {
		i = -i
	}
	for {
		pos--
		buf[pos], i = '0'+byte(i%10), i/10
		if i == 0 {
			if signed {
				pos--
				buf[pos] = '-'
			}
			return string(buf[pos:])
		}
	}
}

func (s *svc) SvcPortQuery(p int32) (svcNps []*model.GetSvcList, err error) {
	namespaceList, err := K8s.ClientSet.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return nil, errors.New("获取命名空间列表失败," + err.Error())
	}
	for _, namespace := range namespaceList.Items {
		svcList, err := K8s.ClientSet.CoreV1().Services(namespace.Name).List(context.TODO(), metav1.ListOptions{})
		if err != nil {
			return nil, errors.New("获取svc列表失败," + err.Error())
		}
		for _, svcListInfo := range svcList.Items {
			currentContainerTime := svcListInfo.CreationTimestamp
			dateOfDifference := utils.SubDays(time.Now(), currentContainerTime.Time)
			if svcListInfo.Spec.Ports[0].NodePort == p {
				nodePort := s.Int32TypeConversion(svcListInfo.Spec.Ports[0].NodePort)
				svcNp := &model.GetSvcList{
					Name:      svcListInfo.Name,
					Namespace: svcListInfo.Namespace,
					Target:    "[Any Node]:" + nodePort + "/" + string(svcListInfo.Spec.Ports[0].Protocol),
					Selector:  svcListInfo.Spec.Selector,
					Type:      string(svcListInfo.Spec.Type),
					Age:       dateOfDifference,
				}
				svcNps = append(svcNps, svcNp)
			}
			return svcNps, nil
		}
	}
	return nil, nil
}

/*
// 更新service
func (s *svc) UpdateService(namespace, content string) (err error) {
	var service = &corev1.Service{}

	err = json.Unmarshal([]byte(content), service)
	if err != nil {
		logger.Error(errors.New("反序列化失败, " + err.Error()))
		return errors.New("反序列化失败, " + err.Error())
	}

	_, err = K8s.ClientSet.CoreV1().Services(namespace).Update(context.TODO(), service, metav1.UpdateOptions{})
	if err != nil {
		logger.Error(errors.New("更新service失败, " + err.Error()))
		return errors.New("更新service失败, " + err.Error())
	}
	return nil
}

*/
